#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <vector>

using namespace std;
using namespace cv;

#define DETECT_FAST 0
#define DETECT_STAR 2
#define DETECT_SURF 1
#define DETECT_MSER 5

extern "C" {

cv::StarFeatureDetector* stard;
cv::FastFeatureDetector* fastd;
cv::SurfFeatureDetector* surfd;
cv::MserFeatureDetector* mserd;
std::vector<cv::KeyPoint> keypoints;
  
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4View_FindFeatures(JNIEnv* env, jobject thiz, jlong addrGray, jlong addrRgba)
{
    Mat* pMatGr=(Mat*)addrGray;
    Mat* pMatRgb=(Mat*)addrRgba;
    vector<KeyPoint> v;

    FastFeatureDetector detector(50);
    detector.detect(*pMatGr, v);
    for( size_t i = 0; i < v.size(); i++ )
        circle(*pMatRgb, Point(v[i].pt.x, v[i].pt.y), 10, Scalar(255,0,0,255));
}


JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4View_detectAndDrawFeatures(JNIEnv* env, jobject thiz, jlong addrGray, jlong addrRgba, jint feature_type)
{
	static bool firstTime = true;
	
	if (firstTime)
	{
		firstTime = false;
		// Initialize parameters for different detectors
		stard = new cv::StarFeatureDetector(20/*max_size*/, 8/*response_threshold*/, 15/*line_threshold_projected*/, 8/*line_threshold_binarized*/, 5/*suppress_nonmax_size*/);
		fastd = new cv::FastFeatureDetector(50/*threshold*/, true/*nonmax_suppression*/);
		surfd = new cv::SurfFeatureDetector(1600/*hessian_threshold*/, 3/*octaves*/, 1/*octave_layers*/);
		mserd = new cv::MserFeatureDetector(10/*delta*/, 10/*min_area*/, 500/*max_area*/, 0.2/*max_variation*/, 0.7/*min_diversity*/, 2/*max_evolution*/, 1/*area_threshold*/, 5/*min_margin*/, 2/*edge_blur_size*/);
	}
		
	// Pick the correct feature detector
	FeatureDetector* fd = 0;
	switch (feature_type)
	{
		case DETECT_SURF:
			fd = surfd;
			break;
		case DETECT_FAST:
			fd = fastd;
			break;
		case DETECT_STAR:
			fd = stard;
			break;
	    case DETECT_MSER:
	    	fd = mserd;
	    	break;
	  }

	// Get image from pool
	Mat* pMatGr  =(Mat*)addrGray;
    Mat* pMatRgb =(Mat*)addrRgba;
	
	Mat greyimage = *pMatGr; // pool->getGrey(input_idx);
	Mat img = *pMatRgb; //pool->getImage(input_idx);

	// Return if no image is found, or feature detector is invalid
	if (img.empty() || greyimage.empty() || fd == 0)
		return;
		
	// Clear the keypoints vector
	keypoints.clear();
	
	// Detect new keypoints
	fd->detect(greyimage, keypoints);

	// Draw the keypoints on the images
	for (vector<KeyPoint>::const_iterator it = keypoints.begin(); it != keypoints.end(); ++it) {
		// Draw black circles, slightly offset
	    Point2f pt = it->pt;
	    pt.x -= 2;
	    pt.y -= 2;
	    if (feature_type == DETECT_SURF)
	    	circle(img, pt, it->size, Scalar(255,0,0,255));
	    else if (feature_type == DETECT_FAST)
	    	//circle(img, pt, it->size, cvScalar(0, 0, 0, 0), 2);
	    	circle(img, pt, it->size, Scalar(255,0,0,255));
	    else if (feature_type == DETECT_MSER)
	    	circle(img, pt, it->size, Scalar(255,0,0,255));
	    else
	   		circle(img, pt, it->size, Scalar(255,0,0,255));
	    
	    /*// Draw yellow circles
	    pt.x += 2;
	    pt.y += 2;
	    if (feature_type == DETECT_SURF)
	    	circle(img, pt, it->size*0.5, cvScalar(255, 255, 0, 0), 2);
	    else if (feature_type == DETECT_FAST)
		    circle(img, pt, it->size, cvScalar(255, 255, 0, 0), 2);
		else if (feature_type == DETECT_MSER)
		    circle(img, pt, it->size, cvScalar(255, 255, 0, 0), 2);
	    else
		    circle(img, pt, 5, cvScalar(255, 255, 0, 0), 2);
		    */
	}
}

}
